<template>
  <dialog ref="dialogRef" class="create-product-dialog" @close="onNativeClose" @cancel="onDialogCancel">
    <form method="dialog" class="dialog-shell" @submit.prevent>
      <div class="dialog-header">
        <h3 class="dialog-title">新增产品</h3>
        <button type="button" class="ui-close-btn fancy-rotate" @click="close" aria-label="关闭">
          <svg viewBox="0 0 24 24" class="icon-x" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>
        </button>
      </div>
      <div class="dialog-content">
        <div class="search-row">
          <div class="search-box">
            <svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.35-4.35" /></svg>
            <input v-model="materialCode" @keyup.enter="doSearch(1)" placeholder="请输入物料编码或名称" />
          </div>
          <button type="button" class="btn primary" @click="doSearch(1)" :disabled="loading">搜索</button>
        </div>
        <div class="table-wrapper card" v-if="records.length">
          <div class="table-scroll-container">
            <table class="entry-table fancy">
              <thead>
                <tr>
                  <th style="width:120px">分类</th>
                  <th style="width:140px">编码</th>
                  <th>品名</th>
                  <th style="width:100px">录入人</th>
                  <th style="width:150px">录入时间</th>
                  <th style="width:70px">选择</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="row in records" :key="row.materialCode" :class="{ selected: selected?.materialCode===row.materialCode }" @click="selectRow(row)">
                  <td>{{ row.productClass }}</td>
                  <td class="mono">{{ row.materialCode }}</td>
                  <td class="strong" :title="row.materialName">{{ row.materialName }}</td>
                  <td>{{ row.creator }}</td>
                  <td>{{ row.createTime }}</td>
                  <td><input type="radio" :value="row.materialCode" v-model="selectedCode" @click.stop="selectRow(row)" /></td>
                </tr>
                <tr v-if="!records.length"><td colspan="6" class="empty">暂无数据</td></tr>
              </tbody>
            </table>
          </div>
          <div class="pagination">
            <button type="button" class="btn ghost sm" :disabled="page<=1||loading" @click="doSearch(page-1)">上一页</button>
            <span class="pager-info">第 {{ page }} / {{ totalPages }} 页 (共 {{ total }} 条)</span>
            <button type="button" class="btn ghost sm" :disabled="page>=totalPages||loading||totalPages<=1" @click="doSearch(page+1)">下一页</button>
          </div>
        </div>
        <p v-else class="empty-tip" v-if="!loading">暂无数据，请搜索。</p>
        <div v-if="error" class="error-tip">{{ error }}</div>
        <div v-if="loading" class="loading-mask">加载中...</div>
      </div>
      <div class="dialog-actions">
        <button type="button" class="btn secondary" @click="close">取消</button>
        <button type="button" class="btn success" :disabled="!selected || adding" @click="confirmAdd">确认添加</button>
      </div>
    </form>
  </dialog>
</template>

<script setup lang="ts">
// 新增产品弹窗：提供 open() 方法打开；成功添加通过 emit("added", product) 通知父级。
// TODO: 可扩展为多选、条件过滤增强、与后端分页 pageSize 可调。
import { ref, nextTick } from 'vue';
import { apiPost } from '../../../services/http';
import { fetchSkuEncodingDetail } from '../../../services/sku';
import { getPropertiesWithItemsByClassId } from '../../../services/menu';
import { useSkuStore } from '../../../store/sku';

// 现在新增产品仅回传未保存的临时 product + 初始 BOM 行，不直接写入 Store，等待主编辑弹窗保存后再持久化
const emit = defineEmits<{ (e:'added', payload:{ product:any; bomLines:any[] }):void }>();

interface SearchRecord { outsource:boolean; productClass:string; materialCode:string; materialName:string; materialType:string; length:number; boxPackingCount:number; creator:string; createTime:string; company:string; }
// 接口分页字段统一：请求使用 page / pageSize；响应兼容 page/pageSize 或 current/size（后端可能暂未统一，此处做向后兼容）
interface SearchResponse { code:number; data:{ records:SearchRecord[]; total:number; page?:number; pageSize?:number; current?:number; size?:number; pages?:number; totalPages?:number }; msg:string }
interface DetailResponse { code:number; data:any; msg:string }

const skuStore = useSkuStore();

const dialogRef = ref<HTMLDialogElement|null>(null);
const materialCode = ref('');
const loading = ref(false);
const error = ref('');
const records = ref<SearchRecord[]>([]);
const selected = ref<SearchRecord|null>(null);
const selectedCode = ref('');
// 统一内部状态命名：page / pageSize / totalPages / total
const page = ref(1); const pageSize = ref(10); const totalPages = ref(0); const total = ref(0);
const adding = ref(false);
const opened = ref(false);

function open(){
  opened.value = true; selected.value=null; selectedCode.value=''; materialCode.value=''; error.value='';
  nextTick(()=> { const el=dialogRef.value; if(el && !el.open){ el.showModal(); doSearch(1); } });
}
function close(){ const el = dialogRef.value; if(!el) return; el.close(); opened.value=false; }
function onNativeClose(){ opened.value=false; }
function onDialogCancel(e:Event){ e.preventDefault(); close(); }

async function doSearch(targetPage:number){
  loading.value=true; error.value='';
  try {
    page.value=targetPage;
    const payload = {
      current: page.value,
      size: pageSize.value, // 始终使用默认值或用户选择的值
      materialCode: materialCode.value.trim()
    };
    const res:SearchResponse = await apiPost('/api/encoding-platform/search', payload);
    if(res.code!==200) throw new Error(res.msg||'查询失败');
    const data = res.data || ({} as any);
    records.value = data.records || [];
    total.value = data.total || 0;
    pageSize.value = 10; // 强制重置为默认值
    page.value = (data.page ?? data.current ?? page.value);
    totalPages.value = (data.totalPages ?? data.pages ?? (pageSize.value ? Math.ceil(total.value / pageSize.value) : 0));
  } catch(e:any){ error.value = e.message||'查询失败'; }
  finally { loading.value=false; }
}
function selectRow(row:SearchRecord){ selected.value=row; selectedCode.value=row.materialCode; }

// 解析长度字符串为米数值，支持 mm/cm/m，若缺单位默认 mm
function parseLengthToMeters(raw: string | number | null): number {
  if(raw == null) return 0;
  if(typeof raw === 'number') return raw; // 认为已是米
  const v = String(raw).trim();
  if(!v) return 0;
  // 统一移除中文字符与额外空白
  const m = v.match(/^(\d+(?:\.\d+)?)\s*(mm|cm|m)?$/i);
  if(!m){
    // 尝试抽取前导数字
    const numMatch = v.match(/(\d+(?:\.\d+)?)/);
    const num = numMatch ? parseFloat(numMatch[1]) : 0;
    // 需求里提到“除以100”但更合理：若无法识别单位，按 mm 推断
    return num / 1000; // 默认当 mm
  }
  const num = parseFloat(m[1]);
  const unit = (m[2]||'mm').toLowerCase();
  switch(unit){
    case 'mm': return num / 1000;
    case 'cm': return num / 100;
    case 'm': return num;
    default: return num / 1000;
  }
}

// 格式化当前时间为 yyyy-MM-dd HH:mm:ss
function formatDateTime(ts = Date.now()): string {
  const d = new Date(ts);
  const pad = (n: number) => String(n).padStart(2,'0');
  return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

interface FrameStripBomRecord {
  id: string; // 新增时置空
  classId: number | string;
  className: string;
  productType: string;
  invCode: string; // 来源 item.invCode
  name: string; // mouldCode + 空格 + 长度(米)+m
  bomType: string; // 固定 'product'
  attributes: { propertyName: string; propertyValue: string | number; sort?: number }[];
  feeModel: 'fixed' | 'count';
  feeAmount: number; // 默认 0
  createTime: string;
  updateTime: string;
}

function buildFrameStripBomRecords(itemList: any[] | undefined, productType = '通用'): FrameStripBomRecord[] {
  if(!Array.isArray(itemList) || !itemList.length) return [];
  return itemList.map((it, idx) => {
    const mouldCode = it.mouldCode || '';
    const rawLen = it.innerDiameterSize || '';
    const meters = parseLengthToMeters(rawLen);
    // 名称：型号 + 空格 + 2位小数米数 + m
    const metersStr = meters ? meters.toFixed(2) : '0.00';
    const name = `${mouldCode} ${metersStr}m`;
    // 属性：框条型号 + 长度（米值或原始需求“除以100”已按单位转换）
    const attributes = [
      { propertyName: '框条型号', propertyValue: mouldCode, sort: 10 },
      { propertyName: '长度', propertyValue: meters, sort: 20 }
    ];
    const nowStr = formatDateTime();
    return {
      id: '',
      classId: 65,
      className: 'PE框条',
      productType: productType || '通用',
      invCode: '',
      name,
      bomType: 'product',
      attributes,
      feeModel: 'count',
      feeAmount: 0,
      createTime: nowStr,
      updateTime: nowStr
    };
  });
}

// 将上述结构转为当前页面/Store 使用的内部 BOM 行（BomItemMock）
function convertToInternalBomLines(records: FrameStripBomRecord[], itemList: any[], propertyDefinitions?: any[]): any[] {
  return records.map((rec, idx) => {
    const sourceItem = itemList[idx] || {};
    const qty = Number(sourceItem.quantity) || 1;
    const attrObj: Record<string,string> = {};
    const attributeDefinitions: any[] = [];
    rec.attributes.forEach(a => { 
      attrObj[a.propertyName] = String(a.propertyValue);
      // 查找对应属性的后端定义以获取正确的sort值
      const propDef = propertyDefinitions?.find((pd: any) => pd.propertyName === a.propertyName);
      attributeDefinitions.push({
        code: a.propertyName,
        name: a.propertyName,
        control: 'TextBox',
        sort: propDef?.sortId || a.sort || (attributeDefinitions.length + 1) * 10
      });
    });
    return {
      id: '', // 需求：不填充随机 id，保持为空字符串，保存时也传空
      _localId: `local-${Date.now()}-${idx}`, // 前端渲染唯一 key
      type: 'production',
      seq: idx + 1,
      materialName: rec.name,
      materialCode: rec.invCode,
      category: rec.className, // 展示使用保留中文分类名称
      // materialCategory 在编辑弹窗中期望传递的是分类 Id (字符串形式)，之前写入中文导致无法正确回显“PE框条”分类。
      // 这里改为使用 classId，同时后续展示仍依赖 category 字段的中文名。
      materialCategory: String(rec.classId),
      classId: rec.classId,
      costName: rec.name,
      spec: '',
      qty,
      unit: 'pcs',
      lossFactor: 1,
      unitCost: 0,
      attributes: attrObj,
      attributeDefinitions: attributeDefinitions,
      attributeValues: { ...attrObj },
      feeDetail: { mode: rec.feeModel, amount: 0, quantity: qty, currency: 'CNY' }
    };
  });
}

async function confirmAdd(){
  if(!selected.value) return; adding.value=true; error.value='';
  try {
    const d = await fetchSkuEncodingDetail(selected.value.materialCode);
    const product = {
      code: d.materialCode,
      category: d.productClass || '未分类',
      name: d.materialName,
      status: 'pending' as const,
      createdAt: Date.now(),
      updatedAt: Date.now(),
      attributes: {
        客户简称: d.cusShortName || '',
        模具: d.mould || '',
        尺寸: d.buildingSize || d.innerSizeMm || '',
        材质: d.materialQuality || '',
        功能: d.productFun || '',
        形状: d.buildingFinishedShape || '',
        类别: d.productCategories || ''
      }
    };
    // 根据 itemList 自动生成框条类 BOM 行
    const itemList: any[] = Array.isArray(d.itemList) ? d.itemList : [];
    const frameStripRecords = buildFrameStripBomRecords(itemList, '通用');
    
    // 获取框条分类(classId=65)的属性定义，以便正确获取sort值
    let propertyDefinitions: any[] = [];
    try {
      propertyDefinitions = await getPropertiesWithItemsByClassId(65);
    } catch(e) {
      console.warn('获取属性定义失败', e);
      // 失败则使用默认的sort值
    }
    
    const internalBomLines = convertToInternalBomLines(frameStripRecords, itemList, propertyDefinitions);
    // 写入 store 的初始 BOM
    // 不直接写入 store，交由父组件在保存成功后入库；仅回传临时 BOM 行
    emit('added', { product, bomLines: internalBomLines });
    close();
  } catch(e:any){ error.value = e.message||'添加失败'; }
  finally { adding.value=false; }
}

// 暴露方法供父级调用
defineExpose({ open, close });
</script>

<style scoped>
.create-product-dialog { border:none; padding:0; border-radius:20px; width:900px; max-width:95vw; box-shadow:0 12px 32px -8px rgba(15,23,42,.3),0 4px 18px -6px rgba(15,23,42,.18); }
.create-product-dialog::backdrop { background:rgba(15,23,42,.55); }
.dialog-shell { display:flex; flex-direction:column; max-height:calc(100dvh - 5rem); background:linear-gradient(145deg,#ffffff,#f8fafc 60%,#f1f5f9); }
.dialog-header { display:flex; justify-content:space-between; align-items:center; padding:1rem 1.4rem .85rem; border-bottom:1px solid #e2e8f0; background:linear-gradient(135deg,#ffffff,#f8fafc); }
.dialog-title { margin:0; font-size:20px; font-weight:700; }
.dialog-content { padding:1rem 1.4rem 1.2rem; overflow-y:auto; display:flex; flex-direction:column; gap:1rem; flex:1; min-height:0; }
.search-row { display:flex; gap:.75rem; align-items:center; flex-wrap:wrap; flex-shrink:0; }
.search-box { display:flex; align-items:center; gap:.5rem; padding:.6rem .8rem; border:1px solid #cbd5e1; border-radius:12px; background:#fff; min-width:260px; transition:all .3s cubic-bezier(.4,0,.2,1); }
.search-box:focus-within { border-color:#3b82f6; box-shadow:0 0 0 4px rgba(59,130,246,.15),0 4px 12px -2px rgba(59,130,246,.2); transform:translateY(-1px); }
.search-icon { width:18px; height:18px; color:#6b7280; }
.search-box input { border:none; outline:none; font-size:14px; flex:1; font-weight:500; color:#374151; }
.btn { position:relative; cursor:pointer; border:1px solid transparent; padding:.6rem 1.1rem; border-radius:12px; font-size:14px; font-weight:600; display:inline-flex; align-items:center; gap:.45rem; transition:all .3s cubic-bezier(.4,0,.2,1); }
.btn.primary { background:linear-gradient(135deg,#3b82f6,#2563eb); color:#fff; border-color:#2563eb; }
.btn.primary:hover { background:linear-gradient(135deg,#2563eb,#1d4ed8); transform:translateY(-2px); }
.btn.secondary { background:#ffffff; border:1px solid #d1d5db; color:#374151; }
.btn.secondary:hover { background:#f8fafc; border-color:#cbd5e1; transform:translateY(-2px); }
.btn.success { background:linear-gradient(135deg,#16a34a,#22c55e); color:#fff; border-color:#16a34a; }
.btn.success:hover { background:linear-gradient(135deg,#15803d,#16a34a); transform:translateY(-2px); }
.btn.ghost { background:rgba(255,255,255,.85); border:1px solid #e2e8f0; color:#374151; }
.btn.ghost.sm { padding:.45rem .75rem; font-size:12px; border-radius:10px; }
.table-wrapper.card { border:1px solid #e2e8f0; border-radius:16px; background:#fff; box-shadow:0 8px 25px -6px rgba(15,23,42,.1),0 3px 10px -2px rgba(15,23,42,.05); padding:.5rem .8rem .7rem; display:flex; flex-direction:column; flex:1; min-height:0; }
.table-scroll-container { overflow-y:auto; flex:1; min-height:0; }
.entry-table { width:100%; border-collapse:separate; border-spacing:0; font-size:13px; }
.entry-table thead th { background:linear-gradient(135deg,#f8fafc,#f1f5f9); font-weight:700; font-size:11px; letter-spacing:.05em; text-transform:uppercase; color:#475569; position:sticky; top:0; z-index:1; border-bottom:2px solid #e2e8f0; }
.entry-table th,.entry-table td { padding:.55rem .7rem; text-align:left; }
.entry-table tbody tr { cursor:pointer; transition:background .25s; }
.entry-table tbody tr.selected { background:linear-gradient(135deg,#dbeafe,#bfdbfe); }
.entry-table tbody tr:hover { background:linear-gradient(135deg,#f1f5f9,#e2e8f0); }
.entry-table td.mono { font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; font-size:12px; }
.entry-table td.strong { font-weight:600; }
.pagination { display:flex; align-items:center; gap:.6rem; justify-content:flex-end; padding:.6rem .4rem .2rem; flex-shrink:0; border-top:1px solid #f1f5f9; margin-top:.5rem; }
.pager-info { font-size:11px; color:#475569; }
.empty-tip { color:#64748b; text-align:center; padding:2rem 0; font-size:14px; font-weight:500; }
.loading-mask { position:absolute; inset:0; background:rgba(255,255,255,.6); display:flex; align-items:center; justify-content:center; font-size:16px; font-weight:600; }
.error-tip { color:#dc2626; font-size:12px; }
.dialog-actions { display:flex; justify-content:flex-end; gap:.8rem; padding:.75rem 1.3rem .9rem; border-top:1px solid #e2e8f0; background:linear-gradient(135deg,#ffffff,#f8fafc); }
.icon-x { width:20px; height:20px; }
.ui-close-btn { background:none; border:1px solid transparent; cursor:pointer; padding:.45rem; border-radius:12px; color:#64748b; transition:all .35s cubic-bezier(.4,0,.2,1); display:flex; align-items:center; justify-content:center; }
.ui-close-btn.fancy-rotate:hover { background:linear-gradient(135deg,#fee2e2,#fecaca); color:#dc2626; transform:rotate(90deg); box-shadow:0 4px 14px -4px rgba(220,38,38,.35); }
.create-product-dialog[open] { animation:popIn .45s cubic-bezier(.16,1,.3,1); }
@keyframes popIn { from {opacity:0; transform:translateY(8px) scale(.95);} to {opacity:1; transform:translateY(0) scale(1);} }
</style>
